﻿/* 
 * Copyright 2010 Justin Pealing
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */

using System;
using System.Text.RegularExpressions;

namespace Minnow.Web
{
    /// <summary>
    /// Enumeration of mapping types.
    /// </summary>
    public enum LocalMappingState
    {
        /// <summary>
        /// Indicates that the request Url maps onto a local file.
        /// </summary>
        File,
        /// <summary>
        /// Indicates that the request Url maps onto a local directory.
        /// </summary>
        Folder,
        /// <summary>
        /// Indicates that the request Url maps onto a local file or directory.
        /// </summary>
        FileOrFolder,
        /// <summary>
        /// Indicates that the request Url does not map onto a local file or directory.
        /// </summary>
        None
    }

    /// <summary>
    /// A mapping between request criteria and a handler to process that request
    /// </summary>
    public class HandlerMapping
    {
        private Regex requestRegex;

        /// <summary>
        /// Initialises a new instance of <see cref="Minnow.Web.HandlerMapping"/> for the given request path and handler.
        /// </summary>
        /// <param name="RequestPath">The request path filter.</param>
        /// <param name="Handler">The handler that should handle the request</param>
        public HandlerMapping(string RequestPath, RequestHandler Handler)
            : this(RequestPath, LocalMappingState.File, Handler)
        {

        }

        public HandlerMapping(string RequestPath, LocalMappingState LocalState, RequestHandler Handler)
        {
            this.RequestPath = RequestPath;
            this.Handler = Handler;
            this.LocalState = LocalState;
        }

        /// <summary>
        /// Gets and sets the request path filter that the request Url file name should match.
        /// </summary>
        /// <example>"*.aspx" "WebResource.axd"</example>
        public string RequestPath
        {
            get
            {
                return this.requestPath;
            }
            set
            {
                this.requestRegex = WildcardToRegex(value);
                this.requestPath = value;
            }
        }
        private string requestPath;

        /// <summary>
        /// Indicates whether or not the file / folder being mapped to must exist or not.
        /// </summary>
        /// <remarks>
        /// Defaults to File.
        /// </remarks>
        public LocalMappingState LocalState
        {
            get;
            set;
        }

        /// <summary>
        /// Gets and sets the handler that should handle the request.
        /// </summary>
        public RequestHandler Handler
        {
            get;
            set;
        }

        /// <summary>
        /// Checks to see if a request matches the request path wildcard expression.
        /// </summary>
        /// <param name="Request">The file name part of the request Url</param>
        /// <returns>True if the given request matches the wildcard request path</returns>
        public bool Matches(string Request)
        {
            return this.requestRegex.IsMatch(Request == null ? string.Empty : Request);
        }

        /// <summary>
        /// Determines if the local mapping state (i.e. whether or not the local path maps onto a file etc...) matches the mapping criteria
        /// </summary>
        /// <param name="Status">The local mapping state.</param>
        /// <returns>True if the local mapping state given matches the mapping criteria, false otherwise.</returns>
        public bool Matches(LocalMappingState Status)
        {
            switch (this.LocalState)
            {
                case LocalMappingState.File:
                    return Status == LocalMappingState.File;
                case LocalMappingState.FileOrFolder:
                    return Status == LocalMappingState.File || Status == LocalMappingState.Folder;
                case LocalMappingState.Folder:
                    return Status == LocalMappingState.Folder;
                default:
                    return true;
            }
        }

        /// <summary>
        /// Converts the given wildcard string into a <see cref="System.Text.RegularExpressions.Regex"/>.
        /// </summary>
        /// <param name="Value">Wildcard string.</param>
        /// <returns>A Regex equivalent to the given wildcard expression.</returns>
        private Regex WildcardToRegex(string Value)
        {
            string pattern = "^" + Regex.Escape(Value).Replace("\\*", ".*") + "$";
            return new Regex(pattern);
        }
    }
}
